///
/// Copyright (C) 2016, Dependable Systems Laboratory, EPFL
/// Copyright (C) 2016, Cyberhaven
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///

#ifndef S2E_PLUGINS_RecipeRegister_H_
#define S2E_PLUGINS_RecipeRegister_H_

#include <inttypes.h>
#include <string>

#include <klee/util/Ref.h>

namespace s2e {
namespace plugins {
namespace recipe {

class Register {
public:
    typedef uint8_t Reg;

private:
    static const char *s_regs32[];
    static const char *s_regs64[];

    Reg m_reg = -1;
    uint8_t m_bits = 0;
    uint8_t m_idx = 0;

    Register() {
    }

    Register(Reg regIdx, uint8_t bits, uint8_t idx) : m_reg(regIdx), m_bits(bits), m_idx(idx) {
        assert(bits == 32 || bits == 64);
        assert(!(bits == 32) || ((regIdx < 9) && (idx < 4)));
        assert(!(bits == 64) || ((regIdx < 17) && (idx < 8)));
    }

public:
    // These are required for klee::ref<>
    unsigned refCount = 0;
    bool permanent = false;
    bool temporary = false;

    static klee::ref<Register> fromName(const std::string &name, unsigned byteIdx);
    static klee::ref<Register> fromIndex(Reg reg, uint8_t bits);
    std::string name() const;

    bool operator==(const Register &rhs) const {
        return compare(rhs) == 0;
    }

    uint8_t reg() const {
        return m_reg;
    }
    uint8_t bits() const {
        return m_bits;
    }
    uint8_t idx() const {
        return m_idx;
    }

    bool isPc() const;

    int compare(const Register &b) const {
        return m_reg - b.m_reg;
    }
};
} // namespace recipe
} // namespace plugins
} // namespace s2e

#endif
